{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ff172989-8c38-47e9-8235-df4ee5ac4a77",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch import nn,optim\n",
    "from torch.autograd import Variable\n",
    "from torch.utils.data import DataLoader\n",
    "from torchvision import datasets, transforms"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "fb54104e-9d84-4bce-89ff-25e297989c32",
   "metadata": {},
   "outputs": [],
   "source": [
    "batch_size = 32\n",
    "learning_rate = 0.01\n",
    "num_epoches = 100"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "86a78a45-ba77-439a-b7df-43b48c355702",
   "metadata": {},
   "outputs": [],
   "source": [
    "#带有激励函数和批标准化的网络\n",
    "class Batch_Net(nn.Module):\n",
    "    def __init__(self, in_dim, n_hidden_1, n_hidden_2,n_hidden_3,n_hidden_4,out_dim):\n",
    "        super(Batch_Net, self).__init__()\n",
    "        self.layer1 = nn.Sequential(nn.Linear(in_dim,n_hidden_1),nn.BatchNorm1d(n_hidden_1),nn.ReLU(True))\n",
    "        self.layer2 = nn.Sequential(nn.Linear(n_hidden_1,n_hidden_2),nn.BatchNorm1d(n_hidden_2),nn.ReLU(True))\n",
    "        self.layer3 = nn.Sequential(nn.Linear(n_hidden_2,n_hidden_3),nn.BatchNorm1d(n_hidden_3),nn.ReLU(True))\n",
    "        self.layer4 = nn.Sequential(nn.Linear(n_hidden_3,n_hidden_4),nn.BatchNorm1d(n_hidden_4),nn.ReLU(True))\n",
    "        self.layer5 = nn.Sequential(nn.Linear(n_hidden_4,out_dim))\n",
    "    def forward(self, x):\n",
    "        x = self.layer1(x)\n",
    "        x = self.layer2(x)\n",
    "        x = self.layer3(x)\n",
    "        x = self.layer4(x)\n",
    "        x = self.layer5(x)\n",
    "        return x\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c9fa2629-4af4-4177-b43f-e3a5a76e54f3",
   "metadata": {},
   "outputs": [],
   "source": [
    "#对数据进行标准化预处理\n",
    "data_tf = transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5],[0.5])])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "6f39ebd3-8f5d-4649-b820-577958f354b6",
   "metadata": {},
   "outputs": [],
   "source": [
    "#导入Mnist数据集\n",
    "train_dataset = datasets.MNIST(root='./data',train=True,transform=data_tf)\n",
    "test_dataset = datasets.MNIST(root='./data',train=False,transform=data_tf)\n",
    "train_loader = DataLoader(train_dataset,batch_size=batch_size,shuffle=True)\n",
    "test_loader = DataLoader(test_dataset,batch_size=batch_size,shuffle=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "6215593e-ca70-41cf-80bb-439f8d3b279d",
   "metadata": {},
   "outputs": [],
   "source": [
    "#导入神经网络，定义损失与优化\n",
    "model = Batch_Net(28*28,400,300,200,100,10)\n",
    "model = model.cuda()   #模型放到gpu里，因为等下数据会放到gpu计算\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = optim.SGD(model.parameters(),lr = learning_rate)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "fb5dcbf0-4260-4e4d-8a72-f47e157f3788",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch:100,loss:0.8407\n",
      "epoch:200,loss:0.5883\n",
      "epoch:300,loss:0.4157\n",
      "epoch:400,loss:0.3873\n",
      "epoch:500,loss:0.3045\n",
      "epoch:600,loss:0.4552\n",
      "epoch:700,loss:0.2829\n",
      "epoch:800,loss:0.1889\n",
      "epoch:900,loss:0.1259\n",
      "epoch:1000,loss:0.2209\n",
      "epoch:1100,loss:0.2861\n",
      "epoch:1200,loss:0.06091\n",
      "epoch:1300,loss:0.08705\n",
      "epoch:1400,loss:0.4102\n",
      "epoch:1500,loss:0.08869\n",
      "epoch:1600,loss:0.1033\n",
      "epoch:1700,loss:0.346\n",
      "epoch:1800,loss:0.2911\n"
     ]
    }
   ],
   "source": [
    "#训练模型\n",
    "epoch = 0\n",
    "for data in train_loader:\n",
    "    img, label = data\n",
    "    #print(img)\n",
    "    #print(img.size())\n",
    "    #img是batch_size张1*28*28的向量，使用view()函数把他变成batch_size张一维向量\n",
    "    img = img.view(img.size(0),-1)\n",
    "    img = img.cuda()\n",
    "    label = label.cuda()\n",
    "    out = model(img)\n",
    "    loss = criterion(out, label)\n",
    "    print_loss = loss.data.item()\n",
    "    optimizer.zero_grad()    #每一批训练集中梯度的累计计算的，但是下一批训练集的梯度应该重新计算而不是继续累计本次的梯度\n",
    "    loss.backward()\n",
    "    optimizer.step()\n",
    "    epoch += 1\n",
    "    if(epoch % 100 == 0):\n",
    "        print('epoch:{},loss:{:.4}'.format(epoch, loss.data.item()))\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "e4936830-5ceb-47fe-b1a0-b6b6f3bf8704",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test loss:0.111351,Acc:0.969600\n"
     ]
    }
   ],
   "source": [
    "#测试模型\n",
    "model.eval()\n",
    "eval_loss = 0\n",
    "eval_acc = 0\n",
    "for data in test_loader:\n",
    "    img, label = data\n",
    "    img = img.view(img.size(0),-1)\n",
    "    img = img.cuda()\n",
    "    label = label.cuda()\n",
    "    out = model(img)\n",
    "    loss = criterion(out, label)\n",
    "    eval_loss += loss.data.item()*label.size(0)\n",
    "    #out是64*10的向量，max函数找出第二个维度最大的向量\n",
    "    _,pred = torch.max(out,1)     #返回两个向量，第一个向量保存最大的数值，第二个向量保存最大的值的索引（下标）,\n",
    "                                  #_,pred 表示不关心最大数值的向量，pred只保存索引\n",
    "    num_correct = (pred == label).sum()\n",
    "    eval_acc += num_correct.item()\n",
    "    \n",
    "print('Test loss:{:.6f},Acc:{:.6f}'.format(eval_loss/(len(test_dataset)), eval_acc/len(test_dataset)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5f308c85",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "280cd4ca",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "63daa1eb",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pytorch",
   "language": "python",
   "name": "pytorch"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
